Skip to content

[LWD] feat(desktop): renew analytics consent from policyVersion - #20263

Open
tonykhaov wants to merge 1 commit into
feat/debug-LIVE-29595-analytics-consent-qafrom
feat/desktop-LIVE-29592-analytics-consent-renewal
Open

[LWD] feat(desktop): renew analytics consent from policyVersion#20263
tonykhaov wants to merge 1 commit into
feat/debug-LIVE-29595-analytics-consent-qafrom
feat/desktop-LIVE-29592-analytics-consent-renewal

Conversation

@tonykhaov

@tonykhaov tonykhaov commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

✅ Checklist

  • npx changeset was attached.
  • Covered by automatic tests.
  • Impact of the changes:
    • Portfolio analytics consent dialog: major bump / missing consent → full reconsent; minor bump → privacy ack only
    • Optional analytics tracking gate while renewal is pending
    • Privacy "Got it" keeps the existing consent date
    • Developer QA consent screen predictions follow the shared decision

📝 Description

Desktop still decided consent renewal with live-common helpers: a rolling consentValidityDays window plus a flat numeric privacy version compare. That missed the ADR split where a major policyVersion bump forces full analytics reconsent and a minor bump only asks for privacy acknowledgement.

This PR points Ledger Wallet Desktop at @features/flow-analytics-consent the same way mobile already does. The dialog, tracking gate, settings persist path, and QA screen all use that shared verdict. Fresh choices (accept / decline / confirm preferences) write a new consent date and the normalized policy version. Privacy-only acknowledgement updates the version and leaves the consent date alone. Stale analytics consent (decision.kind === "renewal") turns optional tracking off until the user chooses again. Invalid remote policyVersion does not invent a prompt from version checks.

consentValidityDays stays on the feature flag for now and is no longer read by the desktop decision path. A follow-up stack layer will drop that field and prune leftover live-common / expiry paths.

Stack layer 7 on #20212 (debug tip).

❓ Context


🧐 Checklist for the PR Reviewers

  • The code aligns with the requirements described in the linked JIRA or GitHub issue.
  • The PR description clearly documents the changes made and explains any technical trade-offs or design decisions.
  • There are no undocumented trade-offs, technical debt, or maintainability issues.
  • The PR has been tested thoroughly, and any potential edge cases have been considered and handled.
  • Any new dependencies have been justified and documented.
  • Performance considerations have been taken into account. (changes have been profiled or benchmarked if necessary)

Made with Cursor

Copilot AI review requested due to automatic review settings July 31, 2026 06:30
@live-github-bot live-github-bot Bot added the desktop Has changes in LLD label Jul 31, 2026
@live-github-bot live-github-bot Bot changed the title feat(desktop): renew analytics consent from policyVersion (LIVE-29592) [LWD] feat(desktop): renew analytics consent from policyVersion (LIVE-29592) Jul 31, 2026
@tonykhaov tonykhaov changed the title [LWD] feat(desktop): renew analytics consent from policyVersion (LIVE-29592) [LWD] feat(desktop): renew analytics consent from policyVersion Jul 31, 2026
@tonykhaov
tonykhaov marked this pull request as ready for review July 31, 2026 06:32
@tonykhaov
tonykhaov requested review from a team as code owners July 31, 2026 06:32
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Web Tools Build Status

Build Status Deployment
Web Tools Build ✅ Deployed https://web-tools-m6x4nxx2d-ledger-hq-prd.vercel.app
Native Storybook Build ✅ Deployed https://native-ui-storybook-itpc624uf-ledger-hq-prd.vercel.app
React Storybook Build ✅ Deployed https://react-ui-storybook-bxdejpsz3-ledger-hq-prd.vercel.app

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates Ledger Wallet Desktop’s analytics-consent renewal logic away from legacy live-common helpers to the shared @features/flow-analytics-consent decision engine, aligning desktop behavior with the major/minor policyVersion semantics and shared tracking gate.

Changes:

  • Switched desktop consent decision + phase resolution (dialog, tracking gate, QA screen) to @features/flow-analytics-consent and the @domain/entity-analytics-consent consent info type.
  • Updated consent persistence paths so full reconsent writes a new consent date, while privacy-only acknowledgement updates the policy version without changing the consent date.
  • Updated unit/integration tests to cover major bump renewal vs minor bump privacy acknowledgement, and invalid remote policyVersion behavior.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pnpm-lock.yaml Adds workspace deps, but also includes broad unrelated lockfile churn (see comment).
apps/ledger-live-desktop/package.json Adds @features/flow-analytics-consent and @domain/entity-analytics-consent dependencies.
.changeset/calm-desks-renew.md Declares a Desktop minor bump for the consent renewal behavior change.
apps/ledger-live-desktop/src/renderer/reducers/settings.ts Updates tracking gate to use shared consent decision; aligns consent info typing with domain entity.
apps/ledger-live-desktop/src/renderer/reducers/settings.test.ts Reworks tracking-enabled tests for major/minor bump + invalid remote version cases.
apps/ledger-live-desktop/src/renderer/actions/settings.ts Changes setAnalyticsConsentInfo to accept the full AnalyticsConsentInfo object.
apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx Updates QA consent screen to display the shared decision and simulate major-bump/renewal scenarios.
apps/ledger-live-desktop/src/mvvm/features/AnalyticsOptInPrompt/hooks/useCommonLogic.tsx Persists consent info using the new shape and reads normalized policy version from shared params.
apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/types.ts Updates consent phase types import to the shared package.
apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/hooks/useAnalyticsConsentDialogViewModel.ts Uses shared decision hook + phase resolver; implements privacy-only ack persistence behavior.
apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/components/AnalyticsConsentDialogIllustration.tsx Updates consent phase type import.
apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/components/AnalyticsConsentDialogFooterActions.tsx Updates consent phase type import.
apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/components/AnalyticsConsentDialogCopyBlock.tsx Updates consent phase type import.
apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/tests/useAnalyticsConsentDialogViewModel.test.ts Updates VM tests for major/minor bump behavior and consentDate preservation on privacy ack.
apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/integrations/AnalyticsConsentDialog.portfolio.integration.test.tsx Updates integration coverage for privacy-only acknowledgement + state persistence expectations.

Comment thread pnpm-lock.yaml
Comment on lines 1679 to 1685
version: 2.3.1(@ledgerhq/device-management-kit@1.7.1(rxjs@7.8.2))
'@ledgerhq/crypto-icons':
specifier: 'catalog:'
version: 2.0.4(@ledgerhq/lumen-design-core@0.1.23)(@ledgerhq/lumen-ui-rnative@0.1.52(e185c177b115a51380796750601a5dcf))(react-native@0.81.6(patch_hash=fbb22f6ab81c7336a446f504c4aef2f23fc558838854399c868c5590e29ac9f1)(@babel/core@7.28.5)(@react-native-community/cli@18.0.1(@typescript/typescript6@6.0.2))(@types/react@19.0.14)(react@19.1.4))(react@19.1.4)
version: 2.0.4(@ledgerhq/lumen-design-core@0.1.23)(@ledgerhq/lumen-ui-rnative@0.1.52(4a7216fe4cd1a636a0648780ad0a82ce))(react-native@0.81.6(patch_hash=fbb22f6ab81c7336a446f504c4aef2f23fc558838854399c868c5590e29ac9f1)(@babel/core@7.28.5)(@react-native-community/cli@18.0.1(@typescript/typescript6@6.0.2))(@types/react@19.0.14)(react@19.1.4))(react@19.1.4)
'@ledgerhq/device-intent':
specifier: workspace:^
version: link:../../libs/device-intent
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

Found 7 projects in monorepo, 7 projects with changes.

📊 Quick Summary
Project Total Size Change
desktop-main 2.3 MB -
desktop-preloader 7.1 KB -
desktop-renderer 80.6 MB -
desktop-webviewDappPreloader 36.9 KB -
desktop-webviewPreloader 200.0 B -
desktop-workers 36.8 KB -
mobile 261.4 MB -
📋 Detailed Reports (Click to expand)

📁 desktop-main

Path: rsdoctor/desktop-main/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 2.3 MB - -
📄 JavaScript 2.2 MB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 135.3 KB - -

📁 desktop-preloader

Path: rsdoctor/desktop-preloader/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 7.1 KB - -
📄 JavaScript 5.3 KB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 1.8 KB - -

📁 desktop-renderer

Path: rsdoctor/desktop-renderer/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 80.6 MB - -
📄 JavaScript 29.3 MB - -
🎨 CSS 183.1 KB - -
🌐 HTML 1.8 KB - -
📁 Other Assets 51.2 MB - -

📁 desktop-webviewDappPreloader

Path: rsdoctor/desktop-webviewDappPreloader/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 36.9 KB - -
📄 JavaScript 36.9 KB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 0 B - -

📁 desktop-webviewPreloader

Path: rsdoctor/desktop-webviewPreloader/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 200.0 B - -
📄 JavaScript 200.0 B - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 0 B - -

📁 desktop-workers

Path: rsdoctor/desktop-workers/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 36.8 KB - -
📄 JavaScript 36.8 KB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 0 B - -

📁 mobile

Path: rsdoctor/mobile/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 261.4 MB - -
📄 JavaScript 110.4 MB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 151.0 MB - -

Generated by Rsdoctor GitHub Action

@live-github-bot

live-github-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Desktop Bundle Checks

Comparing 2e9e6f2 against 5e31ac5.

✅ Previous issues have all been fixed.

Mobile Bundle Checks

Comparing 2e9e6f2 against 078967a.

✅ Previous issues have all been fixed.

Copilot AI review requested due to automatic review settings July 31, 2026 09:23
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-renewal branch from 5e5b0d8 to c9f36d2 Compare July 31, 2026 09:24
@github-actions

Copy link
Copy Markdown
Contributor

❌ Action Required: Monitored Files Changed

The following files in monitored folders have been modified:

  • .github/workflows/test-mobile-e2e-reusable.yml

Action Required: Please rebase your branch against develop to ensure consistency:

git rebase origin/develop

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ E2E tests are required

Changes detected require e2e testing before merge (even before asking for any review).

🖥️ Desktop

-> Run Desktop E2E

  • Select "Run workflow"
  • Branch: feat/desktop-LIVE-29592-analytics-consent-renewal
  • Device: nanoSP or stax

📱 Mobile

-> Run Mobile E2E

  • Select "Run workflow"
  • Branch: feat/desktop-LIVE-29592-analytics-consent-renewal
  • Device: nanoX

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (2)

apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/hooks/useAnalyticsConsentDialogViewModel.ts:50

  • policyVersion can fall back to the stored privacyPolicyVersion, which may still be a legacy number (e.g. 1). Persisting/tracking that value keeps it unnormalized, even though the new flow expects normalized "<major>.<minor>" versions (and tests now assert "1.0"). Consider normalizing the numeric fallback before using it.
  const policyVersion = currentPolicyVersion?.normalized ?? consentInfo.privacyPolicyVersion;

apps/ledger-live-desktop/src/mvvm/features/AnalyticsOptInPrompt/hooks/useCommonLogic.tsx:37

  • policyVersion falls back to consentInfo.privacyPolicyVersion, which may still be a legacy number (e.g. 1). That would be persisted as-is on submit, leaving the stored policy version unnormalized. Normalizing numeric fallbacks here keeps persisted values consistent with the new "<major>.<minor>" policyVersion format.
  const policyVersion = currentPolicyVersion?.normalized ?? consentInfo.privacyPolicyVersion;

Copilot AI review requested due to automatic review settings July 31, 2026 09:35
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-renewal branch from c9f36d2 to bf73105 Compare July 31, 2026 09:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (1)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx:160

  • The "Stored privacy policy version" status is currently derived from decision.kind !== "none", which also turns the stored-version line red for renewals caused only by an invalid/missing consent date. That makes the QA screen misleading because the stored policy version may still be up to date when renewal is purely date-driven.

Consider flagging an error state here only when the decision is privacy-related, or when renewal is specifically caused by stored version issues / major bump.

                className={`min-w-0 flex-1 body-2 font-medium leading-relaxed ${
                  decision.kind !== "none" ? "text-error" : "text-success"
                }`}

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings July 31, 2026 09:42
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-renewal branch from bf73105 to 4e6a0ec Compare July 31, 2026 09:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (2)

apps/ledger-live-desktop/src/mvvm/features/AnalyticsOptInPrompt/hooks/useCommonLogic.tsx:38

  • policyVersion can fall back to consentInfo.privacyPolicyVersion, which may be a legacy number (e.g. 1) or a non-normalized string (e.g. "1"). That contradicts the PR’s intent of persisting a normalized "<major>.<minor>" version and can lead to mixed formats in persisted settings and analytics payloads.

Consider normalizing legacy values before persisting/tracking (at least normalize pure-integer values to "<n>.0", and keep invalid strings as-is).

  const { currentPolicyVersion } = resolveAnalyticsOptInParams(analyticsOptInFlag);
  const policyVersion = currentPolicyVersion?.normalized ?? consentInfo.privacyPolicyVersion;
  const shouldWeTrack = isTrackingEnabled || !hasSeenAnalyticsOptInPrompt;

apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/hooks/useAnalyticsConsentDialogViewModel.ts:51

  • policyVersion falls back to the stored privacyPolicyVersion, which can still be a legacy number (e.g. 1) or non-normalized string (e.g. "1"). If that value is reused in tracking payloads or persisted on future updates, it can reintroduce mixed policy-version formats even though the shared flow normalizes to "<major>.<minor>".

Normalizing pure-integer values here keeps the persisted/telemetry format consistent without changing behavior for invalid stored versions.

  const { isFeatureEnabled, decision, currentPolicyVersion } =
    useAnalyticsConsentDecision(consentInfo);
  // An invalid remote version must not erase the version the user already acknowledged.
  const policyVersion = currentPolicyVersion?.normalized ?? consentInfo.privacyPolicyVersion;

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
66.7% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

desktop Has changes in LLD

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants